<template>
  <div class="svg-container">
    <div class="rooms-example-container">
      <p class="title">{{ title }}布局
        <!--<a href="">如何布局？</a>-->
      </p>
      <div class="title-button-first">
        <p class="room-type">房间类型<span>(请拖动各个房间类型模块至楼层布局图中，完成后点击保存)</span></p>
      </div>
      <div class="rooms-example">
        <div class="room" draggable="true"
              v-for="ex in roomsExample"
              :style="'background-color:' + ex.color + ';'"
              @dragstart="dragstart(ex)"
              @dragend="dragend">
          {{ ex.rmTypeName }}
        </div>
      </div>
    </div>
    <div class="rooms-edit-container">
      <div class="title-button">
        <p class="float-type">楼层布局<span>(双击房间进行编辑、点击房间右上角删除)</span></p>
        <span class="room-btns">
        <el-button size="small" @click="save">保存布局</el-button>
        <el-button size="small" @click="reset">重置布局</el-button>
      </span>
      </div>
      <div id="test1" class="svg-border" :style="'width:' + SVG_SIZE.WIDTH + 'px;height:' + SVG_SIZE.HEIGHT + 'px;'">
        <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"
             @contextmenu.prevent
             @mouseup.stop="mouseup"
             @mousemove="mousemove"
             @mousedown="clearActivatedRoom"
             @mouseout="mouseout"
             @dragover="dragover"
             @drop.prevent="drop">
          <a v-for="(room,index) in rooms"
             v-if="rooms"
             @contextmenu="openMenu(index, $event)"
             @mousedown.stop="moveStart(index, $event)"
             @dblclick.stop="renameRoom">
            <rect class="svg-movable"
                  :class="{ 'activated-room' : room === activatedRoom}"
                  :style="'fill:' + room.color + '; stroke:black; fill-opacity:1; stroke-width:' + ROOM_SIZE.STROKE_WIDTH + ';'"
                  :x="room.geometry.x * SVG_SIZE.WIDTH"
                  :y="room.geometry.y * SVG_SIZE.HEIGHT"
                  :width="room.geometry.width * SVG_SIZE.WIDTH"
                  :height="room.geometry.height * SVG_SIZE.HEIGHT"/>
            <text class="svg-movable" :x="(room.geometry.x + room.geometry.width/2) * SVG_SIZE.WIDTH - 14" :y="(room.geometry.y + room.geometry.height/2) * SVG_SIZE.HEIGHT + 10" fill="black">{{ room.rmName }}</text>
          </a>
          <rect class="svg-resizable" style="fill:white; stroke:black; fill-opacity:0; stroke-width:1;" width="5" height="5"
                v-if="activatedRoom"
                @mousedown.stop="resizeStart"
                :x="resizer.x * SVG_SIZE.WIDTH"
                :y="resizer.y * SVG_SIZE.HEIGHT"/>
          <text class="svg-clickable" fill="black"
                v-if="activatedRoom"
                :x="closer.x * SVG_SIZE.WIDTH - 12"
                :y="closer.y * SVG_SIZE.HEIGHT + 12"
                @mousedown.stop
                @click.stop="removeRoom">x</text>
        </svg>
      </div>
      <el-card v-if="menu" class="room-menu"
               :style="menuStyle"
               @click.stop>
        <div class="text item"><el-button @click="removeRoom">删除房间</el-button></div>
        <div class="text item"><el-button @click="renameRoom">重命名房间</el-button></div>
      </el-card>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
  const MODE = {
    NONE: 0,
    MOVE: 1,
    RESIZE: 2
  };
  const SVG_SIZE = {
    WIDTH: window.innerWidth*0.56,
    HEIGHT:  window.innerHeight*0.50,
  };
  const ROOM_SIZE = {
    STROKE_WIDTH: 1,
  }
  const defaultGeo = {
    x: 0.001,
    y: 0.001,
    width: 0.12,
    height: 0.2,
  }

  import roomApi from '../../service/corporation/roomApi'
  export default {
    props: ["flId", "title"],
    watch: {
      flId(flId) {
        if(flId) {
          this.init();
        }
        console.log("change")
      }
    },
    data() {
      return {
        SVG_SIZE,
        ROOM_SIZE,
        dragObj: "",  // 正在拖动的房间样本
        roomsExample: [],  // 房间样本
        rooms: [],  // 房间布局数据
        originRooms: [], // 复制原始数据的深拷贝，用于重置布局
        activatedRoom: null,  // 当前激活房间
        mode: MODE.NONE,  // 当前激活房间正在进行的操作：无/移动/缩放,
        menu: null,
      }
    },
    computed: {
      resizer() {
        return {
          x: this.activatedRoom.geometry.x + this.activatedRoom.geometry.width,
          y: this.activatedRoom.geometry.y + this.activatedRoom.geometry.height,
        }
      },
      closer() {
        return {
          x: this.activatedRoom.geometry.x + this.activatedRoom.geometry.width,
          y: this.activatedRoom.geometry.y,
        }
      },
      menuStyle() {
        let style = null;
        if(this.menu) {
          style = {
            border: '1px',
            solid: '#f00',
            position: 'absolute',
            left: this.menu.x  * SVG_SIZE.WIDTH - 290 + 'px',
            top: this.menu.y  * SVG_SIZE.HEIGHT - 135 + 'px',
          }
        }
        return style;
      }
    },
    methods: {
      init() {
        this.getData();
      },
      getData() {
        // 清除编辑样式
        this.clearActivatedRoom();
        // 获取房间类型样例
        roomApi.getRoomTypeExamples().then(res => {
          this.roomsExample = res.body.data;
          roomApi.getRoomGeo(this.flId).then(response => {
            this.rooms = response.body.data;
            // 属性设置
            this.handleRoomsData();
          }, response => {});
        }, res => {});
      },
      handleRoomsData() {
        if(!this.rooms) {
          this.rooms = [];
        }
        if(this.roomsExample && this.rooms) {
          for(var room of this.rooms) {
            // 给房间设置颜色
            let color = this.roomsExample.find(ex => {
              return ex.rmTypeId === room.rmTypeId;
            }).color;
            this.$set(room, "color", color);
            // 解析几何信息
            room.geometry = JSON.parse(room.geometry);
          }
          this.originRooms = JSON.parse(JSON.stringify(this.rooms));
        }
      },
      // 判断图形是否超出svg区域
      outOfArea(geo) {
        let flag = false;
        if(geo) {
          let x = geo.x;
          let y = geo.y;
          let width = geo.width;
          let height = geo.height;
          let areaWidth = 1;
          let areaHeight = 1;
          if(x <= 0 ||
            x >= areaWidth - width ||
            y <= 0 ||
            y >= areaHeight - height) {
            flag = true;
          }
        }
        return flag;
      },
      moveStart(index, event) {
        let buttonCode = event.button;
        const CODE_LEFT_MOUTH = 0;
        if(buttonCode === CODE_LEFT_MOUTH) {
          this.activatedRoom = this.rooms[index];
          this.mode = MODE.MOVE;
          this.menu = null;
        }
      },
      mouseup() {
        this.mode = MODE.NONE;
      },
      // 鼠标移出svg区域时终止操作
      mouseout(e) {
        let toEle = e.toElement;  // 鼠标移入的元素
        let svg = document.getElementsByTagName('svg')[0];
        let svgChildren = svg.getElementsByTagName('*');  // svg所有后代
        for(var i=0; i<svgChildren.length; i++) {
          if(svg === toEle || svgChildren[i] === toEle) {
            return ;  // 如果移入元素为svg后代或本身则不终止操作
          }
        }
        // 鼠标移出svg以外区域
        this.mode = MODE.NONE;
      },
      moving(e) {
        // 假设移动后没有出界则继续操作，否则禁止操作
        let mockObj = Object.assign({}, this.activatedRoom.geometry);
        let x = e.movementX  / SVG_SIZE.WIDTH;
        let y = e.movementY  / SVG_SIZE.HEIGHT;
        mockObj.x += x;
        mockObj.y += y;
        if(this.activatedRoom && !this.outOfArea(mockObj)) {
          this.activatedRoom.geometry.x += x;
          this.activatedRoom.geometry.y += y;
        }
      },
      resizeStart(event) {
        let buttonCode = event.button;
        const CODE_LEFT_MOUTH = 0;
        if(buttonCode === CODE_LEFT_MOUTH) {
          this.mode = MODE.RESIZE;
        }
      },
      resizing(e) {
        const minWidth = 0.025;
        const minHeight = 0.04;
        // 假设缩放后大小合理则继续操作，否则禁止操作
        let mockObj = Object.assign({}, this.activatedRoom.geometry);
        let x = e.movementX  / SVG_SIZE.WIDTH;
        let y = e.movementY  / SVG_SIZE.HEIGHT;
        mockObj.width += x;
        mockObj.height += y;
        if(mockObj.width >= minWidth && mockObj.height >= minHeight && !this.outOfArea(mockObj)) {
          this.activatedRoom.geometry.width += x;
          this.activatedRoom.geometry.height += y;
        }
      },
      mousemove(e) {
        if(this.mode === MODE.MOVE) {
          this.moving(e);
        } else if(this.mode === MODE.RESIZE) {
          this.resizing(e);
        }
      },
      clearActivatedRoom() {
        this.activatedRoom = null;
        this.clearMenu();
        this.mode = MODE.NONE;
      },
      openMenu(index, e) {
        this.activatedRoom = this.rooms[index];
        this.mode = MODE.NONE;
        this.menu = {
          x: e.clientX / SVG_SIZE.WIDTH,
          y: e.clientY  / SVG_SIZE.HEIGHT,
        }
        console.log(this.menu)
      },
      clearMenu() {
        this.menu = null;
      },
      dragstart(example) {
        this.dragObj = example;
      },
      dragend() {
        this.dragObj = null;
      },
      drop() {
        if(this.dragObj) {
          let addRoom = {
            rmName: this.dragObj.rmTypeName,
            rmTypeId: this.dragObj.rmTypeId,
            color: this.dragObj.color,
            geometry: Object.assign({}, defaultGeo),
          };
          this.addRoom(addRoom);
        }
      },
      dragover(e) {
        // 只允许拖动指定元素进入svg容器
        if(this.dragObj) {
          e.preventDefault();
        }
      },
      addRoom(addRoom) {
        let handlePosition = (addRoom) => {
          for(let room of this.rooms) {
            if(room.geometry.x === addRoom.geometry.x && room.geometry.y === addRoom.geometry.y) {
              addRoom.geometry.x += 0.01;
              addRoom.geometry.y += 0.01;
              handlePosition(addRoom);
              break;
            }
          }
          return addRoom;
        }
        this.rooms.push(handlePosition(addRoom));
      },
      renameRoom() {
        this.clearMenu();
        let room = this.activatedRoom;
        this.$prompt('请输入房间名', '', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputPattern: /[\S]+/,
          inputErrorMessage: '请输入正确的房间名',
          inputValue: room.rmName,
        }).then(({ value }) => {
          room.rmName = value;
        }).catch(() => {});
      },
      removeRoom() {
        this.clearMenu();
        let removeLocalData = () => {
          // 删除房间数据
          let removeIndex = this.rooms.findIndex((room) => {
            return room === this.activatedRoom;
          });
          this.rooms.splice(removeIndex,1);
          // 删除原始房间数据
          if(this.activatedRoom.rmId) {
            removeIndex = this.originRooms.findIndex((room) => {
              return room.rmId === this.activatedRoom.rmId;
            });
            this.originRooms.splice(removeIndex,1);
          }
          // 删除成功后清除当前激活元素
          this.clearActivatedRoom();
        }
        // 有房间id时提示并远程删除房间，否则只删除本地数据且不提示
        let rmId = this.activatedRoom.rmId;
        if(rmId) {
          this.$confirm('确认删除房间？删除操作不可恢复', '', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            roomApi.removeRoom(rmId).then(res => {
              removeLocalData();
              this.$emit("updateFloor", this.flId);
            }, res => {});
          }).catch(() => {});
        } else {
          removeLocalData();
        }
      },
      save() {
        this.clearActivatedRoom();
        let data = JSON.parse(JSON.stringify(this.rooms));
        for(var d of data) {
          delete d.color;
          d.geometry = JSON.stringify(d.geometry);
        }
        console.log(data);
        roomApi.saveRoomGeo(this.flId, data).then(res => {
          this.rooms = res.body.data;
          this.handleRoomsData();
          this.$emit("updateFloor", this.flId);
        });
      },
      reset() {
        this.clearActivatedRoom();
        this.rooms = JSON.parse(JSON.stringify(this.originRooms));
      },
    },
    mounted() {
      this.init();
    }
  }
</script>

<style>
  .svg-container {
  }
  .svg-movable {
    cursor: move
  }
  .svg-resizable {
    cursor: nw-resize
  }
  .svg-clickable {
    cursor: pointer
  }
  svg text {
    -moz-user-select:none;/*火狐*/
    -webkit-user-select:none;/*webkit浏览器*/
    -ms-user-select:none;/*IE10*/
    -khtml-user-select:none;/*早期浏览器*/
    user-select:none;
  }
  .svg-border {
    border:2px solid #D5D5D5;
    background: url("../../img/shading.png");
  }
  /*.rooms-example-container {*/
    /*margin-bottom: 30px;*/
  /*}*/
  .rooms-example-container .rooms-example {
    /*margin-top: 45px;*/
  }
  .rooms-example-container .room {
    cursor: default;
    border-radius: 5px;
    margin: 8px;
    padding:5px 8px;
    display: inline-block;

  }
  .rooms-example-container .room * {
    cursor: default;
    border-style:solid;
    border-color:black;
  }

  .room-menu {
  }

  .room-menu text {
    font-size: 14px;
  }

  .room-menu .item {
    margin-top: 16px;
  }
  .svg-container .title{
    font-size: 24px;
    color: #21282e;
  }
  .svg-container .title a{
    font-size: 14px;
    color: red;
  }
  .svg-container p.room-type,p.float-type{
    font-size: 18px;
    color: #333333;
    padding:10px 0;
    float: left;
  }
  .svg-container p.room-type span,p.float-type span{
    margin-left: 5px;
    font-size: 14px;
    color: #8c939d;
  }
  .rooms-edit-container .title-button{
    overflow: hidden;
  }
  .rooms-edit-container .room-btns{
    float: right;
    margin-top: 4px;
    margin-right: 100px;
  }
  .svg-container .title-button-first{
    overflow: hidden;
  }
</style>
